﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;

namespace Tools
{
    /// <summary>
    /// Enum
    /// </summary>
    public class EnumUtil
    {
        #region 作废 2011-05-04
        ///// <summary>
        ///// 通过文本得到enum
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="name"></param>
        ///// <returns></returns>
        //public static T GetEnumItem<T>(string name)
        //{
        //    Type type = typeof(T);
        //    if (Enum.IsDefined(type, name))
        //        return (T)Enum.Parse(type, name, true);
        //    //if (Enum.IsDefined(type, "OTHERS"))
        //    //return (T)Enum.Parse(type, "OTHERS", true);
        //    throw new ArgumentException();
        //}

        ///// <summary>
        ///// 得到enum的文本值
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="value"></param>
        ///// <returns></returns>
        //public static string GetEnumName<T>(T value)
        //{
        //    Type type = typeof(T);
        //    return Enum.GetName(type, value);
        //}
        #endregion

        //来自 http://www.cnblogs.com/smalldust/archive/2006/04/25/384657.html

        /// <summary>
        /// maps用于保存每种枚举及其对应的EnumMap对象
        /// </summary>
        private static Dictionary<Type, EnumMap> maps;

        /// <summary>
        /// 由于C#中没有static indexer的概念，所以在这里我们用静态方法
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string GetStringFromEnum(Enum item)
        {
            if (maps == null)
            {
                maps = new Dictionary<Type, EnumMap>();
            }

            Type enumType = item.GetType();

            EnumMap mapper = null;
            if (maps.ContainsKey(enumType))
            {
                mapper = maps[enumType];
            }
            else
            {
                mapper = new EnumMap(enumType);
                maps.Add(enumType, mapper);
            }

            return mapper[item];
        }

        /// <summary>
        /// 内嵌类，保存enum各个值和名称的对应关系
        /// </summary>
        private class EnumMap
        {
            private Type internalEnumType;
            private Dictionary<Enum, string> map;

            public EnumMap(Type enumType)
            {
                if (!enumType.IsSubclassOf(typeof(Enum)))
                {
                    throw new InvalidCastException();
                }
                internalEnumType = enumType;
                FieldInfo[] staticFiles = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);

                map = new Dictionary<Enum, string>(staticFiles.Length);

                for (int i = 0; i < staticFiles.Length; i++)
                {
                    if (staticFiles[i].FieldType == enumType)
                    {
                        string description = string.Empty;
                        object[] attrs = staticFiles[i].GetCustomAttributes(typeof(EnumItemDescriptionAttribute), true);
                        description = attrs.Length > 0 ?
                            ((EnumItemDescriptionAttribute)attrs[0]).Description :
                            //若没找到EnumItemDescription标记，则使用该枚举值的名字
                            description = staticFiles[i].Name;

                        map.Add((Enum)staticFiles[i].GetValue(enumType), description);
                    }
                }
            }

            public string this[Enum item]
            {
                get
                {
                    if (item.GetType() != internalEnumType)
                    {
                        throw new ArgumentException();
                    }
                    return map[item];
                }
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class EnumItemDescriptionAttribute : DescriptionAttribute
    {
        private bool replaced;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="description"></param>
        public EnumItemDescriptionAttribute(string description)
            : base(description)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public override string Description
        {
            get
            {
                if (!this.replaced)
                {
                    this.replaced = true;
                    base.DescriptionValue = base.Description;
                }
                return base.Description;
            }
        }
    }
}
